#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>

// Preprocessor directive
#include < iostream >               
using namespace std;

// Global variables

#define ID_DRAW_LINE                    30001
#define ID_DRAW_SQUARE                  30002
#define ID_DRAW_ELLIPSE                 30003

#define ID_FILL_SHAPE                   30004
#define ID_EMPTY_SHAPE                  30005

#define ID_CHOOSE_SHAPE                 41001

// The main window class name.
static TCHAR szWindowClass[] = _T("OOP_PaintBrush_WindowClass");

// The string that appears in the application's title bar.
static TCHAR szTitle[] = _T("Hit Object Oriented Programming - Paint Brush - Window");

HINSTANCE gHinst;
COLORREF  gColor;

// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

/* abstract interface declaration */

class Shape
{
public:
    virtual void Draw (HDC hdc,RECT  rcRect,HBRUSH hBrush) = 0;
    virtual void MoveTo (int newx, int newy) = 0;
    virtual void RMoveTo (int dx, int dy) = 0;
};
			 
/* Class Rectangle */

class RectangleClass : public Shape
{
public:
    RectangleClass (int x, int y, int w, int h,int f);
    virtual void Draw (HDC hdc,RECT  rcRect,HBRUSH hBrush);
    virtual void MoveTo (int newx, int newy);
    virtual void RMoveTo (int dx, int dy);
    virtual void SetX (int newX);
    virtual void SetY (int newY);
    virtual void SetWidth (int newWidth);
    virtual void SetHeight (int newHeight);
    virtual void SetFill (int newFill);
    virtual int  GetFill ();
private:
    int x, y;
    int width;
    int height;
	int fill;
};
    
void RectangleClass::Draw (HDC hdc,RECT  rcRect,HBRUSH hBrush)
{
	Rectangle(hdc, x,y,width,height);
	if (fill==1)
		FillRect(hdc,&rcRect,hBrush);
};

void RectangleClass::MoveTo (int newx, int newy)
{
    x = newx;
    y = newy;
}

void RectangleClass::RMoveTo (int dx, int dy)
{
    x += dx;
    y += dy;
}

void RectangleClass::SetX (int newX)
{
    x = newX;
}

void RectangleClass::SetY (int newY)
{
    y = newY;
}

void RectangleClass::SetWidth (int newWidth)
{
    width = newWidth;
}

void RectangleClass::SetHeight (int newHeight)
{
    height = newHeight;
}

void RectangleClass::SetFill (int newFill)
{
	fill = newFill;
}

int RectangleClass::GetFill ()
{
	return fill;
}

RectangleClass::RectangleClass (int initx, int inity, int initw, int inith,int initfill)
{
    x = initx;
    y = inity;
    width = initw;
    height = inith;
	fill=initfill;
}


/* Class Circle */

class CircleClass : public Shape
{
public:
    CircleClass (int initx, int inity, int initr);
    virtual void Draw ();
    virtual void MoveTo (int newx, int newy);
    virtual void RMoveTo (int dx, int dy);
    virtual void SetRadius (int newRadius);

private:
    int x, y;
    int radius;
};

void CircleClass::Draw ()
{
    cout << "Drawing a Circle at (" << x << "," << y
	 << "), radius " << radius << "\n";
}

void CircleClass::MoveTo (int newx, int newy)
{
    x = newx;
    y = newy;
}

void CircleClass::RMoveTo (int dx, int dy)
{
    x += dx;
    y += dy;
}

void CircleClass::SetRadius (int newRadius)
{
    radius = newRadius;
}

CircleClass::CircleClass (int initx, int inity, int initr)
{
    x = initx;
    y = inity;
    radius = initr;
}

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    wcex.hCursor        = LoadCursor(NULL, IDC_CROSS);
	wcex.hbrBackground  = (HBRUSH) GetStockObject (WHITE_BRUSH);
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

    if (!RegisterClassEx(&wcex))
    {
        MessageBox(NULL,
            _T("Call to RegisterClassEx failed!"),
            _T("Hit Object Oriented Programming - Paint Brush - Windowr"),
            NULL);

        return 1;
    }

    gHinst = hInstance; // Store instance handle in our global variable

    // The parameters to CreateWindow explained:
    // szWindowClass: the name of the application
    // szTitle: the text that appears in the title bar
    // WS_OVERLAPPEDWINDOW: the type of window to create
    // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
    // 500, 100: initial size (width, length)
    // NULL: the parent of this window
    // NULL: this application does not have a menu bar
    // hInstance: the first parameter from WinMain
    // NULL: not used in this application
    HWND hwnd = CreateWindow(
        szWindowClass,
        szTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        623,470,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    if (!hwnd)
    {
        MessageBox(NULL,
            _T("Call to CreateWindow failed!"),
            _T("Hit Object Oriented Programming - Paint Brush - Window"),
            NULL);

        return 1;
    }

    // The parameters to ShowWindow explained:
    // hWnd: the value returned from CreateWindow
    // nCmdShow: the fourth parameter from WinMain
    ShowWindow(hwnd,
        nCmdShow);
    UpdateWindow(hwnd);

    // Main message loop:
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//


LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc = (HDC) wParam ;
	HBRUSH hBrush;
	RECT  rcRect;
    
	static int pFill=0;

	Shape * shapes[2];
	RectangleClass * rect= new RectangleClass (0, 0, 15, 15,0);

	static int   cxMove, cxClient, cyMove, cyClient;

	switch (message)
    {
    case WM_CREATE:
		// Create Choose Shape Windows
		CreateWindow(TEXT("button"), TEXT("Choose Option:"), WS_CHILD | WS_VISIBLE | BS_GROUPBOX ,2, 5,110, 125, hwnd, (HMENU) ID_CHOOSE_SHAPE, gHinst, NULL);
		
		CreateWindow(TEXT("button"), TEXT("Line"),WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON ,7, 30, 100, 25, hwnd, (HMENU)ID_DRAW_LINE , gHinst, NULL);
		CreateWindow(TEXT("button"), TEXT("Empty Shape"),WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,7, 60, 100, 25, hwnd, (HMENU)ID_EMPTY_SHAPE , gHinst, NULL);
		CreateWindow(TEXT("button"), TEXT("Fill Shape"),WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,7, 90, 100, 25, hwnd, (HMENU)ID_FILL_SHAPE , gHinst, NULL);
        break;
	 case WM_COMMAND:
		 {
			 switch(LOWORD(wParam))
			 {
				case ID_DRAW_LINE:
					//pShape=ID_DRAW_LINE;
				break; 
				case ID_DRAW_SQUARE:
					//pShape=ID_DRAW_SQUARE;
				break; 
				case ID_DRAW_ELLIPSE:
					//pShape=ID_DRAW_ELLIPSE;
				break; 
				case ID_FILL_SHAPE:
					pFill=1;
				break;
				case ID_EMPTY_SHAPE:
					pFill=0;
				break;
			 }
		 break;
		 }
    case WM_CTLCOLORSTATIC: 
		 {   
			 //SetBkMode( hdc, TRANSPARENT ); 
			 SetBkColor(hdc,RGB(255,255,255));
			 SetTextColor( hdc, RGB( 0,0,0 ) );   
			 return ( INT_PTR )GetStockObject( HOLLOW_BRUSH); 
		 }
		 break;
    case WM_LBUTTONDOWN: 
		  cxClient=LOWORD(lParam);
		  cyClient=HIWORD(lParam);
		 break;
    case WM_MOUSEMOVE:
		  cxMove=LOWORD(lParam);
		  cyMove=HIWORD(lParam);
		 break;
    case WM_LBUTTONUP:
		 {


			InvalidateRect(hwnd,NULL,TRUE);
		 }
	     break;
	 case WM_GETMINMAXINFO:
		 {
			LPMINMAXINFO pMMI = (LPMINMAXINFO)lParam;
			pMMI->ptMinTrackSize.x = 625;
			pMMI->ptMinTrackSize.y = 530;
		 }
		 break;
	case WM_SIZE:
		 {
		 }
	     break;
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);

		rect->SetX(cxClient);
		rect->SetY(cyClient);
		rect->SetWidth(cxMove);
		rect->SetHeight(cyMove);

		rcRect.left=cxClient;
		rcRect.top=cyClient;
		rcRect.right=cxMove;
		rcRect.bottom=cyMove;

		hBrush = CreateSolidBrush(BLACK_BRUSH);
		if(pFill)
			rect->SetFill(1);

		rect->Draw (hdc,rcRect,hBrush);

        EndPaint(hwnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
        break;
    }

    return 0;
}
